YYModel 没有好的 如果变量为nil 替换一个默认变量,OC 中 NSString 经常容易nil 崩溃, 所以有了此次需求,
注: 有一定的性能损失, 但是无需求的话不实现替换方法,性能损失应该很小, 有需求,用性能换稳定应该也划算
NSObject+YYMolde.h 新增
1 2 3 4 5 6
| 转换完成后执行, 老变量新变量的替换 (只遍历当前类, 忽略父类) @return <#return value description#> */ - (id)oldValueToNewValue:(id)value classTypeName:(const char *)classTypeName;
|
.m 新增
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| * 解析Property的Attributed字符串,参考Stackoverflow */ static const char *getPropertyType(objc_property_t property) { const char *attributes = property_getAttributes(property); char buffer[1 + strlen(attributes)]; strcpy(buffer, attributes); char *state = buffer, *attribute; while ((attribute = strsep(&state, ",")) != NULL) { if (attribute[0] == 'T' && attribute[1] != '@') { return (const char *) [[NSData dataWithBytes:(attribute + 1) length:strlen(attribute) - 1] bytes]; } else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) { return "id"; } else if (attribute[0] == 'T' && attribute[1] == '@') { return (const char *) [[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes]; } } return ""; }
|
检查函数, 在合适的位置调用(model 转换完成后调用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| - (void)checkObj:(NSObject *)obj{ if ([obj respondsToSelector:@selector(oldValueToNewValue:classTypeName:)]){ @try{ unsigned int outCount, i; objc_property_t *properties = class_copyPropertyList([obj class], &outCount); for (i = 0;i<outCount; i++){ objc_property_t property = properties[i]; NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)]; const char * propertyTypeName = getPropertyType(property); id propertyValue = [obj valueForKey:propertyName]; id newValue = [(id<YYModel>)obj oldValueToNewValue:propertyValue classTypeName:propertyTypeName]; if (newValue != propertyValue){ [obj setValue:newValue forKey:propertyName]; } } free(properties); }@catch(NSException *exp){ } } }
|
然后自己的实现model 中 实现, 其他类型判断都可行
1 2 3 4 5 6 7 8 9
| - (id)oldValueToNewValue:(id)value classTypeName:(const char *)classTypeName{ const char * className = NSStringFromClass([NSString class]).UTF8String; if (strncmp(className, classTypeName, strlen(className)) == 0){ if(value == nil || value == NULL){ return @""; } } return value; }
|
重点 - 解析property_getAttributes函数的结果
在整个处理过程中,property_getAttributes函数是关键,因为我们要首先确定Property的类型,才能根据类型赋初值,但是property_getAttributes函数返回的字符串比较“晦涩难懂”:
如下定义的Property:
1 2 3 4 5 6
| @property (copy, nonatomic) NSString *name; @property (strong, nonatomic) NSNumber *number; @property (strong, nonatomic) NSArray *array; @property (assign, nonatomic) NSInteger i; @property (assign, nonatomic) CGFloat f; @property (assign, nonatomic) char *cStr;
|
依次通过property_getAttributes获取的结果是:
1 2 3 4 5 6
| T@"NSString",C,N,V_name T@"NSNumber",&,N,V_number T@"NSArray",&,N,V_array Tq,N,V_i Td,N,V_f T*,N,V_cStr
|
参考 Declared Properties of Objective-C Runtime Programming Guide
我们大概可以知道,T表示Type,后面跟着@表示Cocoa对象类型,后面的表示Property的属性,如Copy、strong等,然后就是变量名。
所以getPropertyType函数的工作就是纯粹的解析字符串,获取T@后面的类型名。
参考
git 地址